﻿using Net.Share;
using System;
using UnityEngine;
using UnityEngine.Serialization;
#if LOCK_STEP
using FLOAT = SoftFloat.sfloat;
using Random = NonLockStep.NRandom;
#else
using FLOAT = System.Single;
using Random = UnityEngine.Random;
#endif

namespace GameDesigner
{
    /// <summary>
    /// 动画模式
    /// </summary>
    public enum AnimationMode
    {
        /// <summary>
        /// 旧版动画
        /// </summary>
        Animation,
        /// <summary>
        /// 新版动画
        /// </summary>
        Animator,
#if SHADER_ANIMATED
        /// <summary>
        /// Shader GPU网格动画
        /// </summary>
        MeshAnimator,
#endif
        /// <summary>
        /// 时间轴可播放导演动画
        /// </summary>
        Timeline,
        /// <summary>
        /// 时间驱动模式
        /// </summary>
        Time,
        /// <summary>
        /// 空状态模式
        /// </summary>
        None,
    }

    /// <summary>
    /// 动画播放模式
    /// </summary>
	public enum AnimPlayMode
    {
        /// <summary>
        /// 随机播放动画
        /// </summary>
		Random,
        /// <summary>
        /// 顺序播放动画
        /// </summary>
		Sequence,
        /// <summary>
        /// 代码控制模式
        /// </summary>
        Code,
    }

    public enum StateType
    {
        None,
        SubStateMachine,
        Parent,
    }

    /// <summary>
    /// 状态 -- v2017/12/6
    /// </summary>
    [Serializable]
    public sealed class State : StateBase
    {
        /// <summary>
        /// 状态连接集合
        /// </summary>
		public Transition[] transitions;
        /// <summary>
        /// 动作系统 使用为真 , 不使用为假
        /// </summary>
		public bool actionSystem;
        /// <summary>
        /// 动画循环?
        /// </summary>
        public bool animLoop = true;
        /// <summary>
        /// 动画模式
        /// </summary>
        public AnimPlayMode animPlayMode;
        /// <summary>
        /// 动作索引
        /// </summary>
		[HideInInspector]
        public int actionIndex = -1;
        /// <summary>
        /// 动画速度
        /// </summary>
		public FLOAT animSpeed = 1;
        /// <summary>
        /// 动画淡入淡出
        /// </summary>
        public bool isCrossFade;
        /// <summary>
        /// 过渡的持续时间
        /// </summary>
        public FLOAT duration = 0.25f;
        /// <summary>
        /// 动画结束是否进入下一个状态
        /// </summary>
        public bool isExitState;
        /// <summary>
        /// 动画结束进入下一个状态的ID
        /// </summary>
        [FormerlySerializedAs("DstStateID")]
        public int dstStateID;
        /// <summary>
        /// 状态动作集合
        /// </summary>
		public StateAction[] actions;
        public StateType Type;
#if STATE_MACHINE_OLD
        public StateMachine subStateMachine;
#endif
        [SerializeField] private RefIdentity subId;
        public RefIdentity SubId { get => subId ??= new(); set => subId = value; }
        public IStateMachine SubStateMachine => stateMachine.Root.SubStateMachines[SubId];

        public State()
        {
        }

#if UNITY_EDITOR
        public void SetNodePosition(Vector2 position)
        {
            base.position = new Rect(position, new Vector2(150, 30));
        }
#endif

        /// <summary>
        /// 构造函数
        /// </summary>
        public State(IStateMachine stateMachine)
        {
            behaviours = new BehaviourBase[0];
            transitions = new Transition[0];
            actions = new StateAction[0];
            this.stateMachine = stateMachine;
            Id = stateMachine.States.Length;
            stateMachine.States = ArrayHelper.Add(stateMachine.States, this);
            ArrayHelper.Add(ref actions, new StateAction() { Id = Id, stateMachine = stateMachine, behaviours = new BehaviourBase[0] });
            stateMachine.UpdateStates();
        }

        /// <summary>
        /// 当前状态动作
        /// </summary>
        public StateAction Action => actions[actionIndex % actions.Length];

        /// <summary>
        /// 进入状态
        /// </summary>
		public void Enter(int childStateId, int actionId, bool eirstEnter)
        {
            if (Type == StateType.SubStateMachine)
            {
                var states = SubStateMachine.States;
                if (childStateId != -1)
                {
                    SubStateMachine.ChangeChildState(childStateId, actionId);
                    return;
                }
                for (int i = 0; i < states.Length; i++)
                {
                    if (states[i].Type == StateType.Parent)
                    {
                        if (states[i].transitions.Length > 0)
                            SubStateMachine.ChangeChildState(states[i].transitions[0].NextId, actionId);
                        else
                            SubStateMachine.ChangeChildState(SubStateMachine.DefaultState.Id, actionId); //需要强制进入，否则可能会不触发行为的OnEnter
                        return;
                    }
                }
                SubStateMachine.ChangeChildState(SubStateMachine.DefaultState.Id, actionId); //没有状态可进就进入默认状态
                return;
            }
            if (Type == StateType.Parent)
            {
                if (stateMachine.Parent == null)
                    return;
                var states = stateMachine.Parent.States;
                for (int i = 0; i < states.Length; i++)
                {
                    if (states[i].SubStateMachine == stateMachine)
                    {
                        if (states[i].transitions.Length > 0)
                            stateMachine.Parent.ChangeChildState(states[i].transitions[0].NextId, actionId);
                        else
                            stateMachine.Parent.ChangeChildState(stateMachine.Parent.DefaultState.Id, actionId);
                        return;
                    }
                }
                stateMachine.Parent.ChangeChildState(stateMachine.Parent.DefaultState.Id, actionId); //没有状态可进就进入默认状态
                return;
            }
            if (animPlayMode == AnimPlayMode.Random)//选择要进入的动作索引
                actionIndex = RandomHelper.Range(0, actions.Length);
            else if (animPlayMode == AnimPlayMode.Sequence)
                actionIndex++;
            else
                actionIndex = actionId;
            for (int i = 0; i < behaviours.Length; i++)
            {
                var behaviour = behaviours[i] as StateBehaviour;
                if (!behaviour.Active)
                    continue;
                if (eirstEnter)
                    behaviour.OnFirstEnter();
                behaviour.OnEnter();
            }
            for (int i = 0; i < transitions.Length; i++)
            {
                var transition = transitions[i];
                transition.time = 0;
            }
            if (actionSystem)
                Action.Enter(this);
            if (eirstEnter)
                stateMachine.Handler.OnStateEnter(this);
        }

        internal void Exit()
        {
            if (Type == StateType.SubStateMachine)
                return;
            if (Type == StateType.Parent)
                return;
            for (int i = 0; i < behaviours.Length; i++)
            {
                var behaviour = behaviours[i] as StateBehaviour;
                if (behaviour.Active)
                    behaviour.OnExit();
            }
            if (actionSystem)
                Action.Exit();
            stateMachine.Handler.OnStateExit(this);
        }

        /// <summary>
        /// 当子动作处于循环播放模式时, 子动作每次播放完成动画都会调用一次
        /// </summary>
        internal void OnActionExit()
        {
            for (int i = 0; i < behaviours.Length; i++)
            {
                var behaviour = behaviours[i] as StateBehaviour;
                if (behaviour.Active)
                    behaviour.OnActionExit();
            }
        }

        /// <summary>
        /// 当动作停止
        /// </summary>
        public void OnActionStop()
        {
            for (int i = 0; i < behaviours.Length; i++)
            {
                var behaviour = behaviours[i] as StateBehaviour;
                if (behaviour.Active)
                    behaviour.OnStop();
            }
        }

        internal void Init(IStateMachine stateMachine, params object[] args)
        {
            this.stateMachine = stateMachine;
            if (Type == StateType.SubStateMachine)
            {
                stateMachine.UpdateRefId(this);
                SubStateMachine.Controller = stateMachine.Controller;
                SubStateMachine.Layer = stateMachine.Layer;
                SubStateMachine.Parent = stateMachine;
                SubStateMachine.Handler = stateMachine.Handler;
                SubStateMachine.Init(args);
            }
            for (int i = 0; i < behaviours.Length; i++)
            {
                var behaviour = behaviours[i].InitBehaviour(stateMachine);
                behaviours[i] = behaviour;
                behaviour.OnInit(args);
            }
            foreach (var transition in transitions)
                transition.Init(stateMachine, args);
            if (actionSystem)
                foreach (var action in actions)
                    action.Init(stateMachine, args);
        }

        internal void Update(StateMachineUpdateMode currMode)
        {
            if (Type == StateType.SubStateMachine)
            {
                SubStateMachine.Execute(currMode);
                return;
            }
            else if (Type == StateType.Parent)
            {
                stateMachine.Parent.Execute(currMode);
                return;
            }
            if (actionSystem)
                Action.Update(this, currMode);
            for (int i = 0; i < behaviours.Length; i++)
            {
                var behaviour = behaviours[i] as StateBehaviour;
                if (behaviour.Active)
                {
                    switch (currMode)
                    {
                        case StateMachineUpdateMode.Update:
                            behaviour.OnUpdate();
                            break;
                        case StateMachineUpdateMode.LateUpdate:
                            behaviour.OnLateUpdate();
                            break;
                        case StateMachineUpdateMode.FixedUpdate:
                            behaviour.OnFixedUpdate();
                            break;
                    }
                }
            }
            for (int i = 0; i < transitions.Length; i++)
                transitions[i].Update(currMode);
            stateMachine.Handler.OnStateUpdate(this, currMode);
        }

        public StateAction AddAction(string clipName, params ActionBehaviour[] behaviours)
        {
            return new StateAction(this, clipName, behaviours);
        }

        public Transition AddTransition(int stateId, params TransitionBehaviour[] behaviours)
        {
            return new Transition(this, stateId, behaviours);
        }

        public Transition AddTransition(int stateId, TransitionMode mode, float exitTime, int actionId, params TransitionBehaviour[] behaviours)
        {
            return new Transition(this, stateId, behaviours)
            {
                mode = mode,
                exitTime = exitTime,
                actionId = actionId,
            };
        }

        /// <summary>
        /// 设置动作结束后进入下一个状态
        /// </summary>
        /// <param name="stateId"></param>
        public void ActionEndTransfer(int stateId)
        {
            isExitState = true;
            dstStateID = stateId;
        }

        public StateAction GetAction(int index)
        {
            return actions[index];
        }

        public void ClearActions()
        {
            actions = new StateAction[0];
        }

        public void RemoveAction(int index)
        {
            ArrayHelper.RemoveAt(ref actions, index);
        }

        public override string ToString()
        {
            return $"{name}";
        }

        /// <summary>
        /// 进入连线状态
        /// </summary>
        public void EnterTransitionState() => EnterTransitionState(dstStateID, 0);

        public void EnterTransitionState(int transitionId, int actionId = 0)
        {
            var transition = transitions[transitionId];
            transition.isEnterNextState = true;
            transition.actionId = actionId;
        }

        public void SetActionProperty(int actionId, string clipName, float animTime, float length, float animTimeMax, params ActionBehaviour[] behaviours)
        {
            actions[actionId].clipName = clipName;
            actions[actionId].length = length;
            actions[actionId].animTime = animTime;
            actions[actionId].animTimeMax = animTimeMax;
            actions[actionId].AddComponent(behaviours);
        }
    }
}